xlv.obj.suggestion={
	extend:function(){
	},
	implement:function(){
		this.implement('xlv.imp.mvc');
		this.implement('xlv.imp.editor');		
	},
	create:function(tag){
		var div=document.createElement((tag||'div'));
		div.setAttribute('xlvobject','xlv.obj.suggestion');
		Element.addClassName(div, 'class_suggestion');
		return div;			
	},
	properties:{
		dmName:null,
		dmPath:null,
		lookupdmName:null,
		lookupdmPath:null,
		lookupdmTextPath:null,
		lookupdmQueryPath:null,
		lookupdmMoveTo:false,
		lookupItemCount:10
	},
	method:{
		construct:function(){
			var v=this.$V;
			Element.addClassName(this,'class_suggestion');
			v.editor=document.createElement('input');
			v.editor.setAttribute('id','xlvid_suggest_input');
			v.editor.setAttribute('type','text');
			this.appendChild(v.editor);
			v.lookup=document.createElement('div');
			v.lookup.setAttribute('id', 'xlvid_suggest_lookup');
			v.table=document.createElement('table');
			v.table.setAttribute('id','xlvid_suggest_table');
			v.lookup.appendChild(v.table);
			v.table.setAttribute('cellpadding','0px');
			v.table.setAttribute('cellspacing','0px');
			v.table.appendChild(v.tbody=document.createElement('tbody'));
			v.tbody.setAttribute('id','xlvid_suggest_body');
			Element.setStyle(v.lookup,{cursor:'default',display:'none'});
			this.styleForId(v.editor,v.editor.id);
			this.styleForId(v.lookup,v.lookup.id);
			this.styleForId(v.table,v.table.id);
			this.styleForId(v.tbody,v.tbody.id);
		},
		initial:function(){
			
			this.addEventHandler('blur','_blur',this.$V.editor);
			this.addEventHandler('focus','_focus',this.$V.editor);
			this.$V.lookupReady=false;
			this.$V.defer_mvc_valueToView=null;
			this.$V._query_timeout=null;
			this.$V._query_timeout2=null;
			this.$V.selectedRow=null;
			this.$V.lastQueryValue=null;
		},
		styleForId:function(facilities,id){
		},
		showLookup:function(visible){
			if(visible){
				var lt=xlv.desktop.viewportOffset(this.$V.editor);
				Element.setStyle(this.$V.lookup,{display:'block',left:lt[0]+'px',top:(lt[1]+this.$V.editor.offsetHeight)+'px',zIndex:xlv.sys.zIndexDnd});
			}else Element.setStyle(this.$V.lookup,{display:'none'});
		},
		_blur:function(event){
			if(this.editor_editing())this._editor_endEdit(true);
		},
		_focus:function(event){
			if(!this.editor_editing())this._editor_startEdit();
		},
		_lookupMouseDown:function(event){
			var target=event.target;
			var row=this.targetElement(target,{tag:'tr'},{tag:'body'});
			this.$V.selectedRow=row;
		},
		refreshLookup:function(dm){
			var v=this.$V;
			dm=(dm||this.mvc_getModel(this.$P.lookupdmName));
			var rows=dm.rows();
			for(var i=0,n=v.tbody.rows.length;i<n;++i)v.tbody.deleteRow(-1);
			this.$V.selectedRow=null;
			for(var i=0;i<rows;++i){
				var row=v.tbody.insertRow(-1);
				row.insertCell(-1);
				if(this.$P.lookupdmTextPath) row.insertCell(-1);
				if(this.valueForLookupRow(dm,i,row)){
					this.styleForLookupRow(v.tbody.rows.length-1,row);
					Element.addClassName(row,((v.tbody.rows.length%2)==0) ?'even':'odd');
				}
				if(v.tbody.rows.length>=this.$P.lookupItemCount)break;
			}
			var length=v.tbody.rows.length;
			if(length>0)Element.addClassName(this.$V.selectedRow=v.tbody.rows[0],'selected');
			this.showLookup((length==0)? false:true);
			this.$V.lastQueryNone=(length==0)?this.$V.lastQueryValue:null;
		},
		styleForLookupRow:function(index,row){
		},
		valueForLookupRow:function(dm,index,row){
			var value=this.mvc_valueFromModel(dm,index);
			if(this.$P.lookupdmQueryPath==null && this.$V.lastQueryValue!=null){
				if(!value.toUpperCase().startsWith(this.$V.lastQueryValue.toUpperCase())){
					this.$V.tbody.deleteRow(-1);
					return false;
				}
			}
			row._dmRowNo=index;
			row._dmValue=value;
			row.cells[0].innerHTML=value.replace(new RegExp('^('+this.$V.lastQueryValue+')', 'img'), '<b>$1</b>');
			if(row.cells[1]&&this.$P.lookupdmTextPath!=null) {
				row.cells[1].innerHTML=dm.map(this.$P.lookupdmPath,value,this.$P.lookupdmTextPath);
			}
			return true;
		},
		_keyup:function(event) {
			var code=(event.keyCode||event.which);
			if(code==37||code==13)return;
			var v=this.$V;
			if(v.selectedRow){
				var rows=v.tbody.rows;
				var row_index=-1;
				switch(code){
					case Event.KEY_DOWN:
						row_index=Math.min(v.selectedRow.rowIndex+1,rows[rows.length-1].rowIndex);
						break;
					case Event.KEY_UP:
						row_index=Math.max(v.selectedRow.rowIndex-1,rows[0].rowIndex);
						break;
					case Event.KEY_HOME:
						row_index=rows[0].rowIndex;
						break;
					case Event.KEY_END:
						row_index=rows[rows.length-1].rowIndex;
						break;
				}
				if(row_index>=0){
					var row=rows[row_index-rows[0].rowIndex];
					if(row!=v.selectedRow){
						Element.removeClassName(v.selectedRow,'selected');
						v.selectedRow=row;
						Element.addClassName(v.selectedRow,'selected');
					}
				}
			}
			if(this.editor_editing()&&v.editor.value != v.lastQueryValue && v.lastQueryValue!=null){
				if(v.lastQueryNone!=null && v.editor.value.startsWith(v.lastQueryNone)) return;
				v.lastQueryValue=v.editor.value;
				if(this.$V._query_timeout)clearTimeout(this.$V._query_timeout);
				this.$V._query_timeout=setTimeout((function(){this._queryLookup(v.lastQueryValue);}).bind(this), 200);
			}
		},
		_queryLookup:function(value,equal){
			if(this.$P.lookupdmQueryPath==null){
				if(!equal)this.refreshLookup();
			}else{
				var lpdm=this.mvc_getModel(this.$P.lookupdmName);
				if(lpdm){
					var node=lpdm.getNode(this.$P.lookupdmQueryPath);
					node.setAttribute('operator',((equal)? '=':'like'));
					xlv.util.setElementValue(node,((equal)?value:value+'%'));
					lpdm.query();
				}
			}
		},
		/**mvc imp*/
		_isModel:function(dm){
			return this.$P.dmName==dm.getName();
		},
		_isLookupModel:function(dm){
			if(this.$P.lookupdmName==dm.getName()){
				dm.setWebObjectProperties({'sql-query':{'row-maximum':this.$P.lookupItemCount}});
				return true;
			}
			return false;
		},
		mvc_isModel:function(dm){
			return (this._isModel(dm)||this._isLookupModel(dm));
		},
		mvc_addListener:function(){
			var dm;
			if(dm=this.mvc_getModel(this.$P.dmName))dm.addListener(this);
			if(dm=this.mvc_getModel(this.$P.lookupdmName))dm.addListener(this);
		},
		mvc_removeListener:function(){
			var dm;
			if(dm=this.mvc_getModel(this.$P.dmName))dm.removeListener(this);
			if(dm=this.mvc_getModel(this.$P.lookupdmName))dm.removeListener(this);
		},
		mvc_valueFromModel:function(dm,index){
			if(this._isModel(dm)) return dm.getValue(this.$P.dmPath);
			if(this._isLookupModel(dm))return dm.getValue(this.$P.lookupdmPath,index+1);
			return null;
		},
		mvc_valueToModel:function(value,dm,index){
			if(this._isModel(dm)) dm.setValue(value,this.$P.dmPath);
			else if(this._isLookupModel(dm))dm.setValue(value,this.$P.lookupdmPath,index+1);
		},
		mvc_beforeModelChanged:function(dm,notify,memo){
			if(this._isModel(dm)&& notify=='cursorMove'&& this.editor_editing())
				this._editor_endEdit(true);
		},
		mvc_modelChanged:function(dm,notify,memo){
			switch(notify){
				case 'nodeChanged':
					if(memo.type=='update'){
						if(this._isLookupModel(dm)&& this.$P.lookupdmPath && memo.src && this.$P.lookupdmPath.endsWith(memo.src.nodeName))
							this.refreshLookup(dm);
						if(this._isModel(dm)&& this.$P.dmPath && memo.src && this.$P.dmPath.endsWith(memo.src.nodeName))
							this.mvc_valueToView(this.mvc_valueFromModel(dm));
					}
					break;
			}
		},
		mvc_afterModelChanged:function(dm,notify,memo){
			var v=this.$V;
			switch(notify){
				case 'setChanged' :
					if(this._isLookupModel(dm)) {
						v.lookupReady=true;
						if(v.defer_mvc_valueToView) {
							v.defer_mvc_valueToView();
							v.defer_mvc_valueToView=null;
						}
						if(v.lookupValueForView!=null){
							var value=dm.map(this.$P.lookupdmPath,v.lookupValueForView,this.$P.lookupdmTextPath);
							if(value!=null){
								v.lookupValueForView=null;
								this.mvc_valueToView(null,value);
							}
						}
						this.refreshLookup(dm);
					}
					break;
				case 'rowChanged':
					if(this._isLookupModel(dm)) this.refreshLookup(dm);
					if(memo.type=='cancel'){
						if(this._isModel(dm)) this.mvc_valueToView(this.mvc_valueFromModel(dm));
					}
					break;
				case 'cursorMove' :
					if(this._isModel(dm)) this.mvc_valueToView(this.mvc_valueFromModel(dm));
					break;
			}
			this.mvc_enableControl(dm);
		},
		mvc_enableControl:function(dm){
		},
		mvc_valueToView:function(value,text){
			var v=this.$V;
			if(value==null&&text!=null){
				v.editor.value=text;
				return;
			}
			v.editor.value='';
			if(!this.$P.lookupdmTextPath) this.$V.editor.value=value;
			else{
				var lpdm=this.mvc_getModel(this.$P.lookupdmName);
				if(v.lookupReady||lpdm.$P.methodName==null){
					if(lpdm && (value!=null && value.length>0)){
						text=lpdm.map(this.$P.lookupdmPath,value,this.$P.lookupdmTextPath);
						if(text!=null) v.editor.value=text;
						else{
							v.lookupValueForView=value;
							if(v._query_timeout2)clearTimeout(v._query_timeout2);
							v._query_timeout2=setTimeout((function(){this._queryLookup(value,true);}).bind(this), 200);
						}
					}
				}else v.defer_mvc_valueToView=(function(){this.mvc_valueToView(value);}).bind(this);
			}
		},
		mvc_valueFromView:function(){
			return this.$V.editor.value;
		},
		/**editor imp*/
		editor_startEdit:function(){
			var v=this.$V;
			xlv.desktop.appendChild(v.lookup);
			this.showLookup(false);
			var dm=this.mvc_getModel();
			if(dm)this.editor_valueToEditor(this.mvc_valueFromModel(dm));
			v.editor.select();
			v.lastQueryValue=v.editor.value;
			this.addEventHandler('keyup','_keyup',v.editor);
			this.addEventHandler('mousedown','_lookupMouseDown',v.tbody);
		},
		editor_valueToEditor:function(value){
			this.editor_properties.originalValue=value;
			this.$V.editor.value=value;
		},
		editor_valueFromEditor:function(){
			return this.$V.editor.value;
		},
		editor_endEdit:function(commit){
			var v=this.$V;
			this.removeObserve('keyup','_keyup',v.editor);
			this.removeObserve('mousedown','_lookupMouseDown',v.tbody);
			if(v.lookup.parentNode)v.lookup.parentNode.removeChild(v.lookup);
			var dm=this.mvc_getModel();
			if(commit){
				var value=(v.selectedRow)?v.selectedRow._dmValue : this.editor_valueFromEditor();
				if(dm){
					if(value==this.editor_properties.originalValue)this.mvc_valueToView(value);
					else this.mvc_valueToModel(value,dm);
				}else this.editor_valueToEditor(value);
				if(this.$P.lookupdmMoveTo && v.selectedRow){
					var lpdm=this.mvc_getModel(this.$P.lookupdmName);
					if(lpdm) lpdm.position(v.selectedRow._dmRowNo);
				}
			}else{
				if(dm)this.mvc_valueToView(this.mvc_valueFromModel(dm));
				else this.editor_valueToEditor(this.editor_properties.originalValue);
			}
		},
		editor_validate:function(){
			return (this.$V.selectedRow != null);
		}
	}
};
